﻿#include "chainmanage.h"
#include "pfpointer.h"
#include "responsechain.h"

#include <tunnel/basetunnel.h>
#include <tunnel/tunnelfactory.h>

#include <data/commonpack.h>
#include <data/initargs.h>
#include <data/readyargs.h>
#include <data/replypacket.h>
#include <data/requestpacket.h>
#include <data/startargs.h>
#include <data/stopargs.h>

#include <serialize/commonpackparser.h>
#include <serialize/commonpackwriter.h>
#include <serialize/readyargsparser.h>
#include <serialize/readyargswriter.h>
#include <serialize/replypacketparser.h>
#include <serialize/replypacketwriter.h>
#include <serialize/requestpacketparser.h>
#include <serialize/requestpacketwriter.h>
#include <serialize/startargsparser.h>
#include <serialize/startargswriter.h>
#include <serialize/stopargsparser.h>
#include <serialize/stopargswriter.h>
#include <QsLog.h>

PFPointer::PFPointer()
    :m_cmdProc(this, true),
      m_dataProc(this, false)
{
    m_dataTunnel = Q_NULLPTR;
    m_cmdTunnel = Q_NULLPTR;
    // 初始解析处理责任链。 TODO 可用模板类重载doData方法。
    m_proceChain = new ChainManage();
    m_proceChain->add(QSharedPointer<ResponseChain>(new ResponseChain(CommonPack::Type_Start, [&](QByteArray data){this->doStart(data);})));
    m_proceChain->add(QSharedPointer<ResponseChain>(new ResponseChain(CommonPack::Type_Stop, [&](QByteArray data){this->doStop(data);})));
    m_proceChain->add(QSharedPointer<ResponseChain>(new ResponseChain(CommonPack::Type_Request, [&](QByteArray data){this->doRequest(data);})));
    m_proceChain->add(QSharedPointer<ResponseChain>(new ResponseChain(CommonPack::Type_Reply, [&](QByteArray data){this->doReply(data);})));
    m_proceChain->add(QSharedPointer<ResponseChain>(new ResponseChain(CommonPack::Type_Ready, [&](QByteArray data){this->doReady(data);})));
}

PFPointer::~PFPointer()
{
    if(m_dataTunnel)
    {
        delete m_dataTunnel;
        m_dataTunnel = Q_NULLPTR;
    }
    if(m_cmdTunnel)
    {
        delete m_cmdTunnel;
        m_cmdTunnel = Q_NULLPTR;
    }
    if(m_proceChain){
        delete m_proceChain;
        m_proceChain = Q_NULLPTR;
    }
}

bool PFPointer::buildDataLink(const IPFiveTuple &args)
{
    TunnelFactory factory(args);
    // 创建隧道连接的业务。
    if(!m_dataTunnel)
    {
        m_dataTunnel = factory.create();
        m_dataTunnel->add(&m_dataProc);
    }
    if(m_dataTunnel->build() == false)
    {
        delete m_dataTunnel;
        m_dataTunnel = Q_NULLPTR;
        onStateChange(PointerCallback::Disconnected, false);
        return false;
    }
    return true;
}

void PFPointer::init(const InitArgs &args)
{
    TunnelFactory factory(args.tuple());
    // 创建隧道连接的业务。
    if(!m_cmdTunnel)
    {
        m_cmdTunnel = factory.create();
        m_cmdTunnel->add(&m_cmdProc);
    }
    if(m_cmdTunnel->build() == false)
    {
        delete m_cmdTunnel;
        m_cmdTunnel = Q_NULLPTR;
        onStateChange(PointerCallback::Disconnected, true);
    }
}

bool PFPointer::start(const StartArgs &args)
{
    if(m_cmdTunnel)
    {
        IPFiveTuple tuple =args.ipTuple();
        IPFiveTuple cmdTuple;
        m_cmdTunnel->fetchTuple(cmdTuple);
        tuple.setRemoteAddr(cmdTuple.localAddr());
        StartArgs startArgs = args;
        startArgs.setIpTuple(tuple);
        QByteArray ary;
        bool bWriterOk =
                writerData<StartArgs, StartArgsWriter>(startArgs, ary, CommonPack::Type_Start);
        if(bWriterOk)
        {
            m_cmdTunnel->write(ary);
        }else {
            //  写入数据失败。
            QLOG_ERROR() << QObject::tr("Start error: write StartArgs data error!");
        }
    }
    return  false;
}

bool PFPointer::stop(const StopArgs &args)
{
    if(m_cmdTunnel)
    {
        QByteArray ary;
        bool bWriterOk =
                writerData<StopArgs, StopArgsWriter>(args, ary, CommonPack::Type_Stop);

        if(bWriterOk)
        {
            m_cmdTunnel->write(ary);
        }else {
            //  写入数据失败。日志。
            QLOG_ERROR() << QObject::tr("stop error: write StopArgs data error!");
        }
    }
    return  false;
}

void PFPointer::request(const RequestPacket &pack)
{
    if(m_dataTunnel)
    {
        QByteArray ary;
        bool bWriterOk =
                writerData<RequestPacket, RequestPacketWriter>(pack, ary, CommonPack::Type_Request);

        if(bWriterOk)
        {
            m_dataTunnel->write(ary);
        }else {
            // 写入数据失败。日志。
            QLOG_ERROR() << QObject::tr("Request error: write RequestPacket data error!");
        }
    }
}

void PFPointer::reply(const ReplyPacket &pack)
{
    if(m_dataTunnel)
    {
        QByteArray ary;
        bool bWriterOk =
                writerData<ReplyPacket, ReplyPacketWriter>(pack, ary, CommonPack::Type_Reply);

        if(bWriterOk)
        {
            m_dataTunnel->write(ary);
        }else {
            // 写入数据失败。日志。
            QLOG_ERROR() << QObject::tr("reply error: write ReplyPacket data error!");
        }
    }
}

void PFPointer::ready()
{
    if(m_cmdTunnel && m_dataTunnel)
    {
        // 从数据链路中取出五元组信息，赋值。
        IPFiveTuple tuple;
        m_dataTunnel->fetchTuple(tuple);
        ReadyArgs args(tuple.localAddr(), tuple.localPort());

        QByteArray ary;
        bool bWriterOk =
                writerData<ReadyArgs, ReadyArgsWriter>(args, ary, CommonPack::Type_Ready);

        if(bWriterOk)
        {
            m_cmdTunnel->write(ary);
        }else {
            // 写入数据失败。日志。
            QLOG_ERROR() << QObject::tr("ready error: write ReadyArgs data error!");
        }
    }else {
        QLOG_ERROR() << QObject::tr("ready process error: tunnel not exists!");
    }
}

void PFPointer::disConnect(bool bCmd)
{
    if(bCmd && m_cmdTunnel)
    {
        m_cmdTunnel->disConnect();
        return;
    }
    if(m_dataTunnel)
    {
        m_dataTunnel->disConnect();
    }
}

void PFPointer::close(bool bCmd)
{
    if(bCmd && m_cmdTunnel)
    {
        m_cmdState = PointerCallback::Unknown;
        m_cmdTunnel->remove(&m_cmdProc);
        m_cmdTunnel->destory();
        delete m_cmdTunnel;
        m_cmdTunnel = Q_NULLPTR;
        return;
    }
    if(m_dataTunnel)
    {
        m_dataState = PointerCallback::Unknown;
        m_dataTunnel->remove(&m_dataProc);
        m_dataTunnel->destory();
        delete m_dataTunnel;
        m_dataTunnel = Q_NULLPTR;
    }
}

void PFPointer::doCommonPack(const CommonPack &srcPack, bool bCmd)
{
    if(!bCmd)
    {
        // 打印日志：仅支持指令链路的命令处理。
        QLOG_WARN() << QObject::tr("Data link receive  command, but it's not expect!");
        return ;
    }
    if(m_proceChain->handle(srcPack) == false)
    {
        QLOG_WARN() << QObject::tr("Receive unhandled command") + srcPack.type();
    }
}

void PFPointer::doStart(QByteArray content)
{
    StartArgs dest;
    if(false == parserData<StartArgs, StartArgsParser>(content, dest))
    {
        QLOG_ERROR() << QObject::tr("Parser StartArgs error!");
        return ;
    }
    BasePointer::onStart(dest);
}

void PFPointer::doStop(QByteArray content)
{
    StopArgs dest;
    if(false == parserData<StopArgs, StopArgsParser>(content, dest))
    {
        QLOG_ERROR() << QObject::tr("Parser StopArgs error!");
        return ;
    }
    BasePointer::onStop(dest);
}

void PFPointer::doRequest(QByteArray content)
{
    RequestPacket dest;
    if(false == parserData<RequestPacket, RequestPacketParser>(content, dest))
    {
        QLOG_ERROR() << QObject::tr("Parser RequestPacket error!");
        return ;
    }
    BasePointer::onRequest(dest);
}

void PFPointer::doReply(QByteArray content)
{
    ReplyPacket dest;
    if(false == parserData<ReplyPacket, ReplyPacketParser>(content, dest))
    {
        QLOG_ERROR() << QObject::tr("Parser ReplyPacket error!");
        return ;
    }
    BasePointer::onReply(dest);
}

void PFPointer::doReady(QByteArray content)
{
    ReadyArgs args;
    if(false == parserData<ReadyArgs, ReadyArgsParser>(content, args))
    {
        QLOG_ERROR() << QObject::tr("Parser ReadyArgs error!");
        return ;
    }
    BasePointer::onReady(args);
}

bool PFPointer::packWrite(int type, const QByteArray &src, QByteArray &dest)
{
    CommonPack packSrc(CommonPack::Type(type), src);
    CommonPackWriter writer;
    Data data;
    bool bWrited = writer.write(packSrc , data);
    if(bWrited){
        dest = data.buffer();
    }
    return bWrited;
}

PFPointer::InnerProc::InnerProc(PFPointer *owner, bool bCmd)
{
    m_owner = owner;
    m_bCmd = bCmd;
}

void PFPointer::InnerProc::onProc(const QByteArray &data)
{
    //  解析接收到的数据、指令并调用对应的操作。
    m_recvBuf.append(data);
    Data srcData(m_recvBuf);
    CommonPackParser commonParser;
    CommonPack srcPack;
    // 解析。
    int parserSize = 0;
    do
    {
        parserSize = commonParser.parse(srcData, srcPack);
        if(parserSize > 0)
        {
            m_recvBuf = m_recvBuf.mid(parserSize);
            srcData.setBuffer(m_recvBuf); //.setOffset(parserSize);
            m_owner->doCommonPack(srcPack, m_bCmd);
        }else if(parserSize < 0){
            //解析失败，主动断开连接。
            QLOG_ERROR() << QObject::tr("Parser CommonPack error, do disconnect! ") <<
                            QObject::tr("receive buffer ") << m_recvBuf.size() <<
                            QObject::tr("(bytes): ") << m_recvBuf.toHex();
            m_owner->disConnect(m_bCmd);
            m_recvBuf.clear();
        }
    } while(parserSize > 0);

}

void PFPointer::InnerProc::onStateChange(bool state)
{
    PointerCallback::State pState = (state) ? PointerCallback::Connected
                                            : PointerCallback::Disconnected;
    //  FIXME 考虑将数据链路连接成功后，状态（ReplyReady）发送到远端，远端开始处理。
    m_owner->onStateChange(pState, m_bCmd);
}
